package yuyue.note02;

import org.junit.Test;
import yuyue.note02.entity.Student;

import java.util.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * stream 相关示例
 */
public class Note02Test {
    @Test
    //Stream初体验
    public void fun1() {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张三", "张三丰", "张卫健", "赵敏", "周芷若");
        for (String str : list) {
            if (str.startsWith("张") && str.length() == 3) {
                System.out.println(str);
            }
        }

        System.out.println("-------------------");

        list.stream().filter(s -> s.startsWith("张")).
                filter(s -> s.length() == 3).
                forEach(System.out::println);
    }

    @Test
    //Collection子接口使用默认方法获取stream
    public void fun2() {
        ArrayList<Object> list = new ArrayList<>();
        Stream<Object> stream = list.stream();

        HashSet<Object> objects = new HashSet<>();
        Stream<Object> stream1 = objects.stream();

        Vector<Object> objects1 = new Vector<>();
        Stream<Object> stream2 = objects1.stream();
    }

    @Test
    //Map的key、value、entrySet单独获取流
    public void fun3() {
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();

        Set<Object> objects = objectObjectHashMap.keySet();
        Stream<Object> stream = objects.stream();

        Stream<Object> stream1 = objectObjectHashMap.values().stream();
    }

    @Test
    //Stream的静态方法 of 获取
    public void fun4() {
        String[] str = {"1", "2", "3"};
        Stream<String> str1 = Stream.of(str);
    }

    @Test
    //foreach 方法
    public void fun5() {
        ArrayList<Object> list = new ArrayList<>();
        Collections.addAll(list, "老子", "庄子", "孟子", "孙子");

        list.stream().forEach(System.out::println);
    }

    @Test
    //count 方法
    public void fun6() {
        ArrayList<Object> list = new ArrayList<>();
        Collections.addAll(list, "老子", "庄子", "孟子", "孙子");

        System.out.println(list.stream().count());
    }

    @Test
    //filter 方法
    public void fun7() {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "老子", "庄子", "孟子", "孙子", "苏星河");

        list.stream().filter(s -> s.length() == 2).forEach(System.out::println);
    }

    @Test
    //limit 方法
    public void fun8() {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "老子", "庄子", "孟子", "孙子", "苏星河");

        list.stream().limit(3).forEach(System.out::println);
    }

    @Test
    //limit 方法
    public void fun9() {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "老子", "庄子", "孟子", "孙子", "苏星河");

        list.stream().skip(6).forEach(System.out::println);
    }

    @Test
    //map 方法
    public void fun10() {
        String[] str = {"11", "22", "33", "44"};

        Stream.of(str).map(Integer::parseInt).forEach(i -> System.out.println(i + 10));
    }

    @Test
    //sorted 方法
    public void fun11() {
        int[] i = {33, 11, 22, 1};
        Stream.of(i).sorted().forEach(System.out::println);//认为只有一个元素，排序方法冗余
        Stream.of(33, 11, 22, 1).sorted().forEach(System.out::println);

        ArrayList<Integer> ints = new ArrayList<>();
        Collections.addAll(ints, 11, 2, 33, 4);
        Stream.of(ints).sorted().forEach(System.out::println);
    }

    @Test
    //sorted 方法
    public void fun12() {
        Stream.of("老子", "庄子", "孟子", "孙子", "苏星河", "孙子")
                .distinct()
                .forEach(System.out::println);
    }

    @Test
    //match 方法
    public void fun13() {
        ArrayList<Integer> integers = new ArrayList<>();
        Collections.addAll(integers, 11, 22, 33, 44);

        boolean b = integers.stream().allMatch(i -> i > 25);
        System.out.println(b);

        boolean b1 = integers.stream().anyMatch(i -> i > 25);
        System.out.println(b1);

        boolean b2 = integers.stream().noneMatch(i -> i > 25);
        System.out.println(b2);
    }

    @Test
    //find 方法
    public void fun14() {
        ArrayList<Integer> integers = new ArrayList<>();
        Collections.addAll(integers, 11, 22, 33, 44);

        Optional<Integer> b = integers.stream().findFirst();
        System.out.println(b);

        b = integers.stream().findAny();
        System.out.println(b);
    }

    @Test
    //max min 方法
    public void fun15() {
        Optional<Integer> max = Stream.of(1, 3, 2, 5, 4).max((o1, o2) -> o1 - o2);
        System.out.println(max.get());

        Optional<Integer> min = Stream.of(1, 3, 2, 5, 4).min((o1, o2) -> o1 - o2);
        System.out.println(min.get());
    }

    @Test
    //reduce 方法
    public void fun16() {
        Integer reduce = Stream.of(1, 3, 2, 5, 4).reduce(7, (a, b) -> {
            System.out.println("a=" + a + "b=" + b);
            return a + b;
        });
        System.out.println(reduce);

        reduce = Stream.of(1, 3, 2, 5, 4).reduce(0, Integer::sum);
        System.out.println(reduce);
    }

    @Test
    //concat 方法
    public void fun17() {
        Stream<String> s1 = Stream.of("胡歌");
        Stream<String> s2 = Stream.of("刘亦菲");

        Stream.concat(s1, s2).forEach(System.out::println);
    }

    ////////////////////////////////////////////////

    @Test
    //收集流的结果到集合
    public void fun18() {
        Stream<String> stream = Stream.of("aa", "bb", "cc");
        //默认集合类型
        List<String> list = stream.collect(Collectors.toList());
        Set<String> set = stream.collect(Collectors.toSet());

        //指定集合类型
        ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
        HashSet<String> hashSet = stream.collect(Collectors.toCollection(HashSet::new));
    }

    @Test
    //收集到数组
    public void fun19() {
        Stream<String> stream = Stream.of("aa", "bb", "cc");
        //默认数组
        Object[] objects = stream.toArray();

        //指定数组
        String[] strings = stream.toArray(String[]::new);
    }

    @Test
    //聚合计算
    public void fun20() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 58, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 99),
                new Student("柳岩", 52, 77));

        //最大值
//        Optional<Student> collect = studentStream.
//                collect(Collectors.maxBy(
//                        (o1, o2) -> o1.getScope() - o2.getScope()));
//        System.out.println(collect.get());

        //最小值
//        Optional<Student> collect1 = studentStream.
//                collect(Collectors.minBy(
//                        (o1, o2) -> o1.getScope() - o2.getScope()));
//        System.out.println(collect1.get());

        //合计
//        int sum = studentStream.collect(Collectors.summingInt(o -> o.getAge()));
//        System.out.println(sum);

        //平均
        Double aDouble = studentStream.collect(Collectors.averagingInt(s -> s.getAge()));
        System.out.println(aDouble);

        //计数
        Long aLong = studentStream.collect(Collectors.counting());
        System.out.println(aLong);
    }

    @Test
    //分组计算
    public void fun21() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 58, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 59),
                new Student("柳岩", 52, 55));

        //age作为分组依据，返回age作为key的map
//        Map<Integer, List<Student>> ageMap =
//                studentStream.collect(Collectors.groupingBy(Student::getAge));
//        System.out.println(ageMap);

        //是否及格作为分组依据，返回是否及格作为key的map
        Map<String, List<Student>> collect = studentStream.collect(Collectors.groupingBy(s -> {
            if (s.getScope() >= 60) {
                return "及格";
            } else {
                return "不及格";
            }
        }));

        collect.forEach((k, v) -> {
            System.out.println(k + "::" + v);
        });
    }

    @Test
    //多级分组
    public void fun22() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 58, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 59),
                new Student("柳岩", 52, 55));

        //多级分组
        Map<Integer, Map<String, List<Student>>> collect =
                studentStream.collect(
                        Collectors.groupingBy(s -> s.getAge(),
                                Collectors.groupingBy(s -> {
            if (s.getScope() >= 90) {
                return "优秀";
            } else if (s.getScope() >= 60) {
                return "及格";
            } else {
                return "不及格";
            }
        })));

        collect.forEach((k, v) -> {
            System.out.println(k + "::" + v);
        });
    }

    @Test
    //分区
    public void fun23() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 58, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 59),
                new Student("柳岩", 52, 55));

        //分区
        Map<Boolean, List<Student>> collect =
                studentStream.collect(Collectors.partitioningBy(
                        student -> student.getScope() > 90));

        collect.forEach((k, v) -> {
            System.out.println(k + "::" + v);
        });
    }

    @Test
    //拼接
    public void fun24() {
        Stream<Student> studentStream = Stream.of(
                new Student("赵丽颖", 58, 95),
                new Student("杨颖", 56, 88),
                new Student("迪丽热巴", 56, 59),
                new Student("柳岩", 52, 55));

        //分区
        String collect = studentStream
                //转换
                .map(Student::getName)
                //delimiter 分隔符，prefix 前缀，suffix 后缀
                .collect(Collectors.joining("|", "start|", "|end"));

        System.out.println(collect);
    }

    @Test
    //并行流获取方式
    public void fun25() {
        ArrayList<Object> list = new ArrayList<>();

        //先获取串行，再获取并行
        Stream<Object> parallel = list.stream().parallel();

        //直接获取并行流
        Stream<Object> objectStream = list.parallelStream();
    }

    @Test
    //验证并行流多线程
    public void fun26(){
        Stream.of(5, 2, 6, 3, 4, 1, 9).parallel().filter(
            s -> {
                System.out.println(Thread.currentThread() + ",s=" + s);
                return true;
            }
        ).count();
    }
}
